package com.imu.purse.api.controller;

import com.google.code.kaptcha.Producer;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.imu.common.annotation.IgnoreAuth;
import com.imu.common.exception.ErrorDesc;
import com.imu.common.exception.ErrorUtil;
import com.imu.common.utils.PhoneUtil;
import com.imu.common.utils.R;
import com.imu.common.validator.Assert;
import com.imu.constant.Constant;
import com.imu.purse.config.GoogleAuthenticatorConfig;
import com.imu.purse.config.PhoneValidate;
import com.imu.purse.modules.app.entity.ImuUserEntity;
import com.imu.purse.modules.app.service.ImuUserService;
import com.imu.purse.modules.base.entity.DictInfo;
import com.imu.purse.modules.base.service.DictInfoService;
import com.imu.purse.modules.sms.SMSAliMessage;
import com.imu.purse.modules.sms.SMSCache;
import com.imu.purse.modules.sms.SMSMessage;
import com.imu.purse.modules.sms.SMSMessage.Type;
import com.imu.purse.modules.sms.entity.SmsLogEntity;
import com.imu.purse.modules.sms.service.SmsLogService;
import com.imu.purse.modules.trade.entity.UserIpEntity;
import com.imu.purse.modules.trade.service.UserIpService;
import com.imu.utils.IPUtils;
import com.xiaoleilu.hutool.log.Log;
import com.xiaoleilu.hutool.log.LogFactory;
import com.xiaoleilu.hutool.util.RandomUtil;
import com.xiaoleilu.hutool.util.StrUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 基础接口
 * 
 * @author chenshun
 * @email sunlightcs@gmail.com
 * @date 2017-03-26 17:27
 */
@RestController
@RequestMapping("/api")
@Api(tags = "基础接口")
public class ApiIndexController extends ApiAbstractController {
	private static Log log = LogFactory.get(ApiIndexController.class);

	/**
	 * 短信验证码 type 0-注册 1-忘记密码 2-提现申请 3-登陆 4-身份认证 7-用户身份识别验证
	 * 
	 */
	@IgnoreAuth
	@PostMapping("message")
	@ApiOperation(value = "发送短信")
	@ApiImplicitParams({
			@ApiImplicitParam(paramType = "body", dataType = "Map", name = "params", value = "{\"phone\":\"手机号\",\"type\":\"0注册1忘记密码2提现\"}", required = true) })
	public R message(HttpServletRequest request, @RequestBody Map<String, Object> params) {
		Assert.isBlank(params.get("phone"), ErrorDesc.PHONE_EMPTY.getMsg(), ErrorDesc.PHONE_EMPTY.getCode());
		Assert.isBlank(params.get("type"), ErrorDesc.TYPE_EMPTY.getMsg(), ErrorDesc.TYPE_EMPTY.getCode());
		Assert.isBlank(params.get("picPass"), ErrorDesc.PHOTO_ACODE_ERROR.getMsg(), ErrorDesc.PHOTO_ACODE_ERROR.getCode());
		String phone = String.valueOf(params.get("phone")); // 手机号
		String picPass = String.valueOf(params.get("picPass"));//图片验证码
		//校验手机号码是否有效
		if(!PhoneUtil.validate(phone)){//无效的手机号码
			return ErrorUtil.errorMesg(request, ErrorDesc.PHONE_ERR);
		}
		if(StrUtil.isEmpty(picPass) || StrUtil.isEmpty(redisTemplate.opsForValue().get(picPass.toLowerCase()))){//验证图片验证码有效性
			return ErrorUtil.errorMesg(request,ErrorDesc.PHOTO_ACODE_ERROR);
		}
		String type = String.valueOf(params.get("type"));

		Type messageType = PhoneValidate.Authentication(type);

		if (messageType == null) {//验证类型
			return ErrorUtil.errorMesg(request, ErrorDesc.TYPE_ERR);
		}


		ImuUserEntity userEntity  = imuUserService.queryByMobile(phone);
		if(!messageType.getType().equals(Type.REGISTER.getType())){//非注册时，校验手机号码是否注册聊
			if(userEntity == null){
				return ErrorUtil.errorMesg(request,ErrorDesc.PHONE_UNREG);
			}
		}else{//注册时
			if(userEntity != null){
				return ErrorUtil.errorMesg(request,ErrorDesc.PHONE_REG);
			}
		}

		if (cache.check(phone)) {//校验1分钟内针对该手机号码是否多次发送短信
			return ErrorUtil.errorMesg(request, ErrorDesc.ACODE_SEND);
		}

		if(userEntity != null){
			phone = StrUtil.isEmpty(userEntity.getInterPhone()) ? phone : userEntity.getInterPhone();
		}
		//验证码1小时5次
		//根据手机号码查询是否存在国际号码
		R  r = checkRateSms(request,phone);
		if(Integer.valueOf(r.get("code").toString()) != 1){
			return r;
		}

		Date nowDate = new Date();
		try {
			SMSMessage message = new SMSMessage();
			message.setRequestTime(nowDate);
			message.setPhone(phone);
			message.setAuthcode(RandomUtil.randomNumbers(Constant.ACODE_LEN));
			message.setType(messageType);
			smsAliMessage.send(message);
		} catch (Exception e) {
			return ErrorUtil.errorMesg(request, ErrorDesc.ACODE_SED_ERR);
		}
		try{
			String ip = IPUtils.getIpAddr(request);
			if(StrUtil.isNotEmpty(ip)){
				UserIpEntity userIpEntity = new UserIpEntity();
				userIpEntity.setIp(ip);
				userIpEntity.setTimeCreate(nowDate);
				userIpService.save(userIpEntity);
			}
		}catch(Exception e){
			logger.error("message",e);
		}

		return R.ok(1);
	}

	/**
	 * 验证码
	 */
	@IgnoreAuth
	@GetMapping("captcha")
	@ApiOperation("获取图片验证码")
	@SuppressWarnings("deprecation")
	public void captcha(HttpServletResponse response) throws ServletException, IOException {
		response.setHeader("Cache-Control", "no-store, no-cache");
		response.setContentType("image/jpeg");

		// 生成文字验证码
		String text = producer.createText();
		// 生成图片验证码
		BufferedImage image = producer.createImage(text);
		// 保存到redis
		// redisTemplate.opsForHash().put(text, text, text);
		redisTemplate.opsForValue().set(text.toLowerCase(), text);
		redisTemplate.expire(text, 3, TimeUnit.MINUTES);
		ServletOutputStream out = response.getOutputStream();
		ImageIO.write(image, "jpg", out);
		IOUtils.closeQuietly(out);
	}

	/**
	 * 生成二维码 验证码生成规则为前台传过来的密钥secretKey
	 * 
	 * @throws WriterException
	 * @throws IOException
	 */
	@IgnoreAuth
	@GetMapping("googleQrCode")
	@ApiOperation("获取google二维码")
	public void googleQrCode(HttpServletResponse response, HttpServletResponse resp, @RequestParam String phone,
			@RequestParam String secretKey) {
		ImuUserEntity imuUser = imuUserService.queryByMobile(phone);
		ServletOutputStream stream = null;
		try {
			int width = 300; // 图像宽度
			int height = 300; // 图像高度
			try {
				stream = resp.getOutputStream();
			} catch (IOException e) {
				e.printStackTrace();
			}
			QRCodeWriter writer = new QRCodeWriter();
			Map<String, Object> map = null;
			try {
				map = GoogleAuthenticatorConfig.GoogleAuthenticator(imuUser.getPhone(), response, secretKey);
			} catch (IOException e) {
				e.printStackTrace();
			}
			BitMatrix m = writer.encode(map.get("qrcode").toString(), BarcodeFormat.QR_CODE, height, width);
			// 将密钥保存到redis (改:密钥前台传入 不在此处保存)
			// redisTemplate.opsForHash().put("googleQrCode",
			// session.getId(),map.get("secrets").toString());
			try {
				MatrixToImageWriter.writeToStream(m, "jpg", stream);
			} catch (IOException e) {
				e.printStackTrace();
			}
		} catch (WriterException e) {
			e.printStackTrace();
		} catch (ServletException e) {
			e.printStackTrace();
		} finally {
			if (stream != null) {
				try {
					stream.flush();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					log.error(e);
				}
				try {
					stream.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					log.error(e);

				}
			}
		}

	}

	@IgnoreAuth
	@PostMapping("increaseRate")
	@ApiOperation("获取汇率")
	public R getIncreaseRate() {
		Map<String, String> map = new HashMap<String, String>();
		List<DictInfo> dictList = dictInfoService.findCahceByCode("IMU_TRANS_RATE");
		if (dictList != null) {
			
			for (DictInfo dictInfo : dictList) {
				
					if (dictInfo.getLabel().equals("IMU_RMB")) {
						map.put(dictInfo.getLabel(), dictInfo.getValue().toString());
					}
					if (dictInfo.getLabel().equals("RMB_GB")) {
						map.put(dictInfo.getLabel(), dictInfo.getValue().toString());
					}
				
			}

		}
		else{
			return R.ok(0);
		}

		return R.ok(1).put("rate", map);
	}

	/**
	 * 校验手机号发送短信数量
	 * 1分钟只允许发送一条短信，一个小时10条，一天30条
	 * @param phone
	 * @return
	 */
	private R checkRateSms(HttpServletRequest request,String phone){
		SmsLogEntity entity = new SmsLogEntity();
		entity.setPhone(phone);
		entity.setTimeCreate(new Date());
		//1分钟内
		entity.setInterval(-1);
		entity.setUnit(Constant.DATE_TAG.MINTURE);
		//用户IP
		UserIpEntity ipEntity = new UserIpEntity();
		ipEntity.setIp(IPUtils.getIpAddr(request));
		ipEntity.setTimeCreate(entity.getTimeCreate());
		ipEntity.setInterval(-1);
		ipEntity.setUnit(Constant.DATE_TAG.MINTURE);
		if(!checkRateSms(entity,ipEntity,Constant.SMS_COUNT.MCOUNT)){
			return ErrorUtil.errorMesg(request,ErrorDesc.SMS_MIN_FREQUENT);
		}
		//1个小时之内
		entity.setUnit(Constant.DATE_TAG.HOUR);
		ipEntity.setUnit(Constant.DATE_TAG.HOUR);
		if(!checkRateSms(entity,ipEntity,Constant.SMS_COUNT.HCOUNT)){
			return ErrorUtil.errorMesg(request,ErrorDesc.SMS_HOU_FREQUENT);
		}
		//1天之类
		entity.setUnit(Constant.DATE_TAG.DAY);
		ipEntity.setUnit(Constant.DATE_TAG.DAY);
		if(!checkRateSms(entity,ipEntity,Constant.SMS_COUNT.DCOUNT)){
			return ErrorUtil.errorMesg(request,ErrorDesc.SMS_DAY_FREQUENT);
		}
		return R.ok(1);
	}

	/**
	 * 校验手机号码或者ip地址在指定时间不允许超过指定数量
	 * @param logEntity
	 * @param ipEntity
	 * @param defaultCount
	 * @return
	 */
	private boolean checkRateSms(SmsLogEntity logEntity, UserIpEntity ipEntity,int defaultCount){
		int count = 0;
		/*if(StrUtil.isNotEmpty(ipEntity.getIp())){ 该处会存在问题，在活动时，所有用户都是使用同一个IP地址
			//先校验IP地址，再校验手机号码
			count = userIpService.queryCountByPhAndTime(ipEntity);
			if(count >= defaultCount){
				return false;
			}
		}*/
		count = smsLogService.queryCountByPhAndTime(logEntity);
		if(count >= defaultCount){
			return false;
		}
		return true;
	}
	@Autowired
	private RedisTemplate<String, String> redisTemplate;

	/*
	 * @Autowired private SendSMS sms;
	 */

	@Autowired
	private SMSCache cache;

	@Autowired
	private DictInfoService dictInfoService;

	@Autowired
	private Producer producer;

	@Autowired
	private ImuUserService imuUserService;

	@Autowired
	private SMSAliMessage smsAliMessage;

	@Autowired
	private SmsLogService smsLogService;

	@Autowired
	private UserIpService userIpService;
}
